package com.atguigu.gulimail.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.utils.R;
import com.atguigu.gulimail.feign.ProductFeignService;
import com.atguigu.gulimail.interceptor.CartInterceptor;
import com.atguigu.gulimail.service.CartService;
import com.atguigu.gulimail.to.UserInfoTo;
import com.atguigu.gulimail.vo.Cart;
import com.atguigu.gulimail.vo.CartItem;
import com.atguigu.gulimail.vo.SkuInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
public class CartServiceImp implements CartService {

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    ProductFeignService productFeignService;


    @Autowired
    ThreadPoolExecutor executor;

    //前缀规则：登录为gulimail:cart+用户id.  临时临时用户为gulimail:cart+userKey
    public static final String CART_PREFIX="gulimail:cart:";

    @Override
    public CartItem addToCart(Long skuId, Integer skuNum) throws ExecutionException, InterruptedException {
        BoundHashOperations cartOpts = getCartOpts();
        String item = (String) cartOpts.get(skuId.toString());

        if (StringUtils.isEmpty(item)){
            //如果为null 说明购物车第一次添加该商品。

            CartItem cartItem=new CartItem();
            CompletableFuture<Void> skuInfoTask = CompletableFuture.runAsync(() -> {
                //1、获取skuInfo的信息
                R r = productFeignService.getSkuInfo(skuId);
                SkuInfoVo data = r.getData("skuInfo", new TypeReference<SkuInfoVo>() {
                });

                cartItem.setSkuId(skuId);
                cartItem.setCount(skuNum);
                cartItem.setCheck(true);
                cartItem.setImage(data.getSkuDefaultImg());
                cartItem.setPrice(data.getPrice());
                cartItem.setTitle(data.getSkuTitle());
            },executor);
            CompletableFuture<Void> skuAttrTask = CompletableFuture.runAsync(() -> {
                //2、通过skuId 获取sku销售属性
                List<String> stringList = productFeignService.skuSaleAttr(skuId);
                cartItem.setSkuAttr(stringList);
            },executor);
                //这里要等两个异步任务都执行完了 之后才继续。
            CompletableFuture.allOf(skuAttrTask,skuInfoTask).get();

            String s = JSON.toJSONString(cartItem);

            //使用skuId 作为hashkey
            cartOpts.put(skuId.toString(), s);
            return cartItem;
        }
        else{
            //否则  就不是第一次添加。
            CartItem cartItem = JSON.parseObject(item, CartItem.class);
            cartItem.setCount(cartItem.getCount()+skuNum);
            String s = JSON.toJSONString(cartItem);

            cartOpts.put(skuId.toString(), s);

            return cartItem;
        }

    }

    /**
     * 通过skuId 获取在Redis数据库中的CartItem
     * @param skuId
     * @return
     */
    @Override
    public CartItem addToCartSuccess(Long skuId) {
        BoundHashOperations cartOpts = getCartOpts();
        String str = (String) cartOpts.get(skuId.toString());
        CartItem cartItem = JSON.parseObject(str, CartItem.class);
        return cartItem;
    }

    @Override
    public Cart cartListPage() throws ExecutionException, InterruptedException {
       Cart cart=new Cart();
        //进入到购物车页面的逻辑。
        //首先要看是否登录。如果登录了。那么就展示登录后的购物车
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        String tempCartKey=CART_PREFIX+userInfoTo.getUserKey();
        if (userInfoTo.getId()!=null){
            // 登录状态
            String loginCartKey=CART_PREFIX+userInfoTo.getId();
            List<CartItem> tempCartItems = getCartItems(tempCartKey);
            if (tempCartItems!=null){
                //如果临时购物车不为null
                //合并购物车。 就是把临时购物车的东西加到购物车里面
                for (CartItem tempCartItem : tempCartItems) {
                    //这个方法 已经封装好了  判定是否登录，登录了就直接添加到登录后的购物车里，
                    addToCart(tempCartItem.getSkuId(),tempCartItem.getCount());
                }
                //合并完之后。清空临时购物车
                clearCart(tempCartKey);
            }
            List<CartItem> cartItems = getCartItems(loginCartKey);
            cart.setItems(cartItems);
        }else {
            //未登录
            List<CartItem> cartItems = getCartItems(tempCartKey);
            cart.setItems(cartItems);
        }
        return cart;

    }

    @Override
    public void clearCart(String cartKeys) {
        stringRedisTemplate.delete(cartKeys);
    }

    @Override
    public void checkItem(String skuId, Integer check) {
        CartItem cartItem = addToCartSuccess(Long.parseLong(skuId));
        cartItem.setCheck((check==1)?true:false);
        BoundHashOperations cartOpts = getCartOpts();
        String s = JSON.toJSONString(cartItem);
        cartOpts.put(skuId, s);
    }

    @Override
    public void changeNum(String skuId, Integer num) {
        CartItem cartItem = addToCartSuccess(Long.parseLong(skuId));
        cartItem.setCount(num);
        BoundHashOperations cartOpts = getCartOpts();
        cartOpts.put(skuId, JSON.toJSONString(cartItem));
    }

    @Override
    public void deleteItem(String skuId) {
        BoundHashOperations cartOpts = getCartOpts();
        cartOpts.delete(skuId);

    }

    @Override
    public List<CartItem> getCartItem() {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        if (userInfoTo.getId()!=null){
            String cartKey=CART_PREFIX+userInfoTo.getId();
            List<CartItem> cartItems = getCartItems(cartKey);
            if (cartItems!=null){
                //这里会出现的问题是。1、cartItems里面的商品是很久之前加的。 那么之前的价格和现在的价格可能不同
                //2、添加到结算清单页面应该是被选中的。
                List<CartItem> collect = cartItems.stream().filter(item -> item.isCheck()).map(cartItem -> {
                    //获取当前商品的最新价格
                    BigDecimal price = productFeignService.price(cartItem.getSkuId());
                    cartItem.setPrice(price);
                    return cartItem;
                }).collect(Collectors.toList());
                return collect;
            }
        }

        return null;
    }

    /**
     * 获取购物车
     * @param cartKey
     * @return
     */
    private List<CartItem> getCartItems(String cartKey) {
        BoundHashOperations<String, Object, Object> operations = stringRedisTemplate.boundHashOps(cartKey);
        //将hash 转换成一个list
        List<Object> values = operations.values();
        if (values!=null&&values.size()>0){
            List<CartItem> cartItems = values.stream().map(o -> {
                String str= (String) o;
                CartItem cartItem = JSON.parseObject(str, CartItem.class);
                return cartItem;
            }).collect(Collectors.toList());
            return cartItems;
        }
        return null;

    }

    /**
     * 封装了一个操作redis数据库的方法。
     * 通过threadLocal获取当前用户是否登录。
     * @return
     */
    private BoundHashOperations getCartOpts() {
        ThreadLocal<UserInfoTo> threadLocal = CartInterceptor.threadLocal;
        UserInfoTo userInfoTo = threadLocal.get();
        String cartKey="";
        if (userInfoTo.getId()!=null){
            //  登录了。 redis中存放就用购物车详情就用 id
            cartKey=CART_PREFIX+userInfoTo.getId();
        }else{
            // 否则就用uuid
            cartKey=CART_PREFIX+userInfoTo.getUserKey();
        }

        BoundHashOperations operations = stringRedisTemplate.boundHashOps(cartKey);
        return  operations;
    }
}
